/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package blink.model;

import java.io.*;
import java.lang.ref.WeakReference;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.ComboBoxModel;
import javax.swing.event.ListDataEvent;
import javax.swing.event.ListDataListener;
import javax.swing.event.TableModelListener;
import javax.swing.table.TableModel;

/**
 * Classe permettant de gérer la persistence des taches dans un dossier.
 * Cette classe peut servir de model à une JList, ComboBox, etc. 
 * @author Jerome David
 */
public class TaskBD implements ComboBoxModel {
    
    private final static String SUFFIX=".tsk";
    private final static String INDEX="tasks.idx";
    
    private int seq=0;
  
    private WeakHashMap<Task,String> cache = new WeakHashMap<Task,String>();
   
    private File directory;  //dossier pour enregistrer les taches
    private List<String> taskNames;
    private List<String> fileNames;
            
    public TaskBD(File d) {
        if (!d.exists()) {
            d.mkdirs();
        }
        else if (!d.isDirectory()) throw new RuntimeException(d.getAbsolutePath()+" is not a directory");
   
        directory=d;
        File index = new File(d,INDEX);
        if (index.exists()) {
            try {
                ObjectInputStream ois = new ObjectInputStream(new FileInputStream(index));
                seq = ois.readInt();
                taskNames = (List<String>) ois.readObject();
                fileNames = (List<String>) ois.readObject();
                ois.close();
                boolean removed=false;
                Iterator<String> fnIt = fileNames.iterator();
                Iterator<String> taskIt = taskNames.iterator();
                while (fnIt.hasNext() && taskIt.hasNext()) {
                    taskIt.next();
                    File f = new File(directory,fnIt.next());
                    if (!f.exists()) {
                       fnIt.remove();
                       taskIt.remove();
                       removed=true;
                    }
                }
                if (removed) {
                    writeIdx();
                }
                
            } catch (Exception ex) {
                Logger.getLogger(TaskBD.class.getName()).log(Level.SEVERE, null, ex);
                taskNames=new ArrayList<String>(); 
                fileNames=new ArrayList<String>(); 
            }
        }
        else {
            taskNames=new ArrayList<String>();
            fileNames=new ArrayList<String>();
        }
    }
    
    public List<String> getTaskNames() {
        return Collections.unmodifiableList(taskNames);
    }
    
    
    public Task getTask(String taskName) {
        int idx = taskNames.indexOf(taskName);
        return getTask(idx); 
    }
    
    
    
    public Task getTask(int idx) {
        String filename=fileNames.get(idx);
        try {
            
            File f = new File(directory,filename);
            ObjectInputStream ois = new ObjectInputStream(new FileInputStream(f));
            Task t = (Task) ois.readObject();
            cache.put(t,filename);
            return t;
        } catch (ClassNotFoundException ex) {
            Logger.getLogger(TaskBD.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            
            Logger.getLogger(TaskBD.class.getName()).log(Level.SEVERE, "Pb with file "+filename, ex);
            
        }
        catch (IndexOutOfBoundsException e) {
             Logger.getLogger(TaskBD.class.getName()).log(Level.INFO, null, e);
        }
        return null;
    }
    
    
    //supprime une tache
    public void removeTask(Task t) {
        if (cache.containsKey(t)) {
            String filename = cache.get(t);
            int idx = fileNames.indexOf(filename);
            taskNames.remove(idx);
            fileNames.remove(idx);
            File f = new File(directory,filename);
            if (f.exists()) f.delete();
            cache.remove(t);
            writeIdx();
            fireRemoved(idx);
        }
    }
    
    
    
    //cree ou remplace une tache
    public int addOrReplaceTask(Task task) {
        boolean fireAdded=false;
        int idx = fileNames.indexOf(cache.get(task));
        // cas nouvelle tache
        if (idx==-1) {
            taskNames.add(task.getName());
            fileNames.add(seq+++SUFFIX);
            writeIdx();
            fireAdded=true;
            idx=taskNames.size()-1;
            
        }
        // cas update nom
        else if(!task.getName().equals(taskNames.get(idx))) {
            taskNames.set(idx,task.getName());
            writeIdx();
        }
        
        writeTask(task,idx);
        if (fireAdded) this.fireAdded(idx);
        else this.fireContentsChanged(idx);
        return idx;
    }
    
    
    
    
    private void writeTask(Task task, int idx) {
        File f = new File(directory,fileNames.get(idx));
        if (f.exists()) f.delete();
        try {
            ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(f));
            oos.writeObject(task);
            oos.close();
        } catch (IOException ex) {
            Logger.getLogger(TaskBD.class.getName()).log(Level.SEVERE, null, ex);
        } 
    }
    

    private String selectedTask;
    @Override
    public void setSelectedItem(Object o) {
        selectedTask=(String) o;
    }

    @Override
    public Object getSelectedItem() {
        return selectedTask;
    }

    @Override
    public int getSize() {
        return taskNames.size();
    }

    @Override
    public Object getElementAt(int i) {
        return taskNames.get(i);
    }
    
    protected ArrayList<ListDataListener> ldls = new ArrayList<ListDataListener>();

    @Override
    public void addListDataListener(ListDataListener ll) {
        ldls.add(ll);
    }

    @Override
    public void removeListDataListener(ListDataListener ll) {
        ldls.remove(ll);
    }
    
    

    private void writeIdx() {
        try {
            File index = new File(directory,INDEX);
            index.delete();
            ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(index));
            oos.writeInt(seq);
            oos.writeObject(taskNames);
            oos.writeObject(fileNames);
            oos.close();
        
        }
        catch (Exception e) {
             Logger.getLogger(TaskBD.class.getName()).log(Level.SEVERE, null, e);
        }
    }
    
    protected void fireContentsChanged(int idx){
        ListDataEvent ev = new ListDataEvent(this, ListDataEvent.CONTENTS_CHANGED, idx, idx);
        for (ListDataListener l : ldls) l.contentsChanged(ev);
    }
    
    protected void fireAdded(int idx){
        ListDataEvent ev = new ListDataEvent(this, ListDataEvent.INTERVAL_ADDED, idx, idx);
        for (ListDataListener l : ldls) l.intervalAdded(ev);
    }
    
     protected void fireRemoved(int idx){
        ListDataEvent ev = new ListDataEvent(this, ListDataEvent.INTERVAL_REMOVED, idx, idx);
        for (ListDataListener l : ldls) l.intervalRemoved(ev);
    }
     
}
